﻿#include <opencv2/opencv.hpp>  //引入openCV
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
	Mat box = imread("D:/h2.jpg");  //读取一张图片
	if (!box.empty())
	{
		//imshow("box", box);  //显示图片
	}

	Mat scene = imread("D:/h1.jpg");  //读取一张图片
	if (!scene.empty())
	{
		//imshow("scene", scene);  //显示图片
	}

	// 创建SIFT特征提取
	auto detector = SIFT::create();
	vector<KeyPoint> keypoints_obj, keypoints_sence;
	Mat descriptors_box, descriptors_sence;
	detector->detectAndCompute(box, Mat(), keypoints_obj, descriptors_box);
	detector->detectAndCompute(scene, Mat(), keypoints_sence, descriptors_sence);
	std::cout << "box keypoints:" << keypoints_obj.size() << std::endl;
	std::cout << "scene keypoints:" << keypoints_sence.size() << std::endl;

	// 初始化flann匹配
	vector<DMatch> matches;
	Ptr<FlannBasedMatcher> matcher = FlannBasedMatcher::create();
	matcher->match(descriptors_box, descriptors_sence, matches);

	// 发现高质量匹配
	std::cout << "total matches:" << matches.size() << std::endl;
	int numOfGood = matches.size() * 0.15;
	std::sort(matches.begin(), matches.end());
	matches.erase(matches.begin() + numOfGood, matches.end());
	std::cout << "good matches:" << matches.size() << std::endl;

	Mat dst;
	drawMatches(box, keypoints_obj, scene, keypoints_sence, matches, dst);
	imshow("OPENCV SIFT 算法测试", dst);

	// 抽取匹配描述子对应的关键点
	std::vector<Point2f> obj_pts;
	std::vector<Point2f> scene_pts;
	for (size_t i = 0; i < matches.size(); i++)
	{
		obj_pts.push_back(keypoints_obj[matches[i].queryIdx].pt);
		scene_pts.push_back(keypoints_sence[matches[i].trainIdx].pt);
	}

	// 对象对齐与单应性矩阵求解
	Mat H = findHomography(obj_pts, scene_pts, RANSAC);
	std::vector<Point2f> obj_corners(4);
	obj_corners[0] = Point(0, 0);
	obj_corners[1] = Point(box.cols, 0);
	obj_corners[2] = Point(box.cols, box.rows);
	obj_corners[3] = Point(0, box.rows);
	std::vector<Point2f> scene_corners(4);

	Mat src = InputArray(obj_corners).getMat(), m = InputArray(H).getMat();
	int depth = src.depth(), scn = src.channels(), dcn = m.rows - 1;
	if (scn + 1 == m.cols) {
		perspectiveTransform(obj_corners, scene_corners, H);

		// 绘制发现的对象
		std::vector<Point> pts;
		for (int i = 0; i < scene_corners.size(); i++) {
			pts.push_back(scene_corners[i]);
		}
		polylines(scene, pts, true, Scalar(0, 0, 255), 2, 8, 0);
	
		// 显示匹配对象
		imshow("匹配结果", scene);
	}

	waitKey(0);
	return 0;
}
